Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

xrange

0 views
Skip to first unread message

Bryan

unread,
Jun 22, 2003, 12:08:55 PM6/22/03
to
in 2.3, what is the best way to write this:

for i in xrange(100): print 'Hello'

i used timeit and it seems that repeat is about 10% faster.

timeit -s"from itertools import repeat" "for i in repeat(None, 100): pass"
100000 loops, best of 3: 10.4 usec per loop

timeit "for i in xrange(100): pass"
100000 loops, best of 3: 11.6 usec per loop

will xrange be obsoleted? what is the best idiom for repeating a loop n
times in 2.3 now where you don't care about the index value?

thanks,

bryan

Peter Hansen

unread,
Jun 22, 2003, 12:14:26 PM6/22/03
to
Bryan wrote:
>
> in 2.3, what is the best way to write this:
> for i in xrange(100): print 'Hello'
>
> i used timeit and it seems that repeat is about 10% faster.

Is such a small performance difference more important to you than
backwards compatibility?

I would choose "for i in xrange()" still, merely because of the
number of people still using Python 2.2 and before, but I'm not
one who cares much about trivial optimizations...

(I realize you might be using 2.3-only features, but I don't think
that automatically means you should abandon readability, by dumping
a well-known idiom with a merely possibly-to-become-idiomatic form.)

-Peter

Bryan

unread,
Jun 22, 2003, 12:26:59 PM6/22/03
to
"Peter Hansen" <pe...@engcorp.com> wrote in message
news:3EF5D5E2...@engcorp.com...

i was trying to think in general terms, not just a simple 100 iterations.
of course for backwards compatibility xrange wins there. to me both xrange
and repeat are similarly readable. i guess i got a bit confused because
python now has two obviously correct way of doing something, and for the
rest of my python life i have to always decide which one to use.

Ken Seehof

unread,
Jun 22, 2003, 1:01:24 PM6/22/03
to

>--
>http://mail.python.org/mailman/listinfo/python-list

The xrange() function has other uses. For example, xrange() can be used
when you want to loop a large number of iterations, where you -do- care about
the index, without allocating memory for a gigantic array of integers (as would
be the case of range()).

Both idioms seem fine to me. It is extremely unlikely that the performance
difference would ever be meaningful, since you would typically have something
going on inside the loop, so the 10% difference would quickly drop below 1%.

From an artistic point of view it bothers me somewhat (but only a little
bit, maybe
0.014%) that there are two equally good ways to express the same thing. Python
is supposed to provide one obvious idiom for each situation. Are we slowing
moving in the direction of Perl?

-Ken

Roman Suzi

unread,
Jun 22, 2003, 12:34:20 PM6/22/03
to

Interesting, what prevents from making xrange-object an iterator? Then there
will be obvious backward compatibility and no need to change idioms.

Sincerely yours, Roman Suzi
--
r...@onego.ru =\= My AI powered by GNU/Linux RedHat 7.3


Sean Ross

unread,
Jun 22, 2003, 2:35:04 PM6/22/03
to

"Ken Seehof" <kse...@neuralintegrator.com> wrote in message
news:mailman.1056301238...@python.org...

>Are we slowing moving in the direction of Perl?

http://info.astrian.net/jargon/terms/c/creeping_featurism.html


Raymond Hettinger

unread,
Jun 22, 2003, 7:44:41 PM6/22/03
to
"Bryan" <bel...@yahoo.com>


What is "best" is a value judgement and varies with the circumstances.
When using Python, following Guido's examples and advice usually
leads to good results.

In general, range(n) is a simple consistent way to go. GvR uses this
is most of his code.

When n gets large enough and/or space becomes enough of an issue
xrange(n) is generally the next best choice. The python library is
full of cases where xrange is used in an inner loop. Personally, I use
xrange for almost everything.

itertools.repeat(obj, n) was not intended to be "second or third way to
do it". It was included in the module to meet a very specific need for
supplying repeated arguments to imap() and ifilter():

cubeiter = imap(operator.pow, count(), repeat(3))

That being said, it does do slightly less work than xrange() because it
doesn't have to create a new object on every iteration. So, it can be
used instead of xrange(n) or [None]*n in situtations where:

1. An interation index is not needed
2. Speed and space are so important that a you can tolerate a less than
beautiful construct like: for _ in itertools.repeat(None, n)

Such a case arises in the code for timeit.py. The beauty and simplicity
of range(n) or xrange(n) is secondary in importance to a key operational
goal for the timer to produce high quality timings which depend on
low timer overhead and minimal impact on memory consumption.
Accordingly, GvR used itertools.repeat(n) in that one situation. AFAICT,
he has never used it elsewhere. That should provide good guidance for
you to do the same

For Py3.0, xrange() will likely go away. Right now, it meets an important
need for an iteration counter that doesn't eat memory for breakfast. For
Py3.0, range() will probably return a fast, memory efficient iterator.


Raymond Hettinger


Chad Netzer

unread,
Jun 22, 2003, 7:27:44 PM6/22/03
to
On Sun, 2003-06-22 at 09:34, Roman Suzi wrote:

> Interesting, what prevents from making xrange-object an iterator? Then there
> will be obvious backward compatibility and no need to change idioms.

In Python 2.3, xrange() returns an iterator in for-loops (thus, it is
faster than it used to be).

However, itertools.repeat() only needs to do an increment like this:

i += 1

whereas, the xrange() iterator does something like this:

i += 1
current = start + i * step_size

which is basically why repeat() is faster. But, if you need a step size
other than one, or are iterating over a range not starting at zero, then
xrange() has the speed and elegance advantage.

As for Bryan's original question, as for whether xrange() will be
obsoleted, the answer seems to be it won't be until/if Python 3 rolls
around, in which case the range() call will likely become a lazy range
object, and list(range()) will be used to explicitly return a list over
the specified range. Until then, xrange() will probably continue to
exist.

There has been discussion on the development list about the possibility
of optimizing away the actual list construction in a "for i in range():"
loop. There is even a proposed patch, but Guido has brought up some
technical objections to the current implementation. It probably won't
happen until 2.4, if it does happen.

--
Chad Netzer <cne...@sonic.net>


Bryan

unread,
Jun 22, 2003, 9:08:08 PM6/22/03
to

> itertools.repeat(obj, n) was not intended to be "second or third way to
> do it". It was included in the module to meet a very specific need for
> supplying repeated arguments to imap() and ifilter():
>
> cubeiter = imap(operator.pow, count(), repeat(3))
>
> Right now, it meets an important
> need for an iteration counter that doesn't eat memory for breakfast. For
> Py3.0, range() will probably return a fast, memory efficient iterator.
>
>
> Raymond Hettinger
>
>

thanks raymond... this is exactly what i was after. i place and purpose for
repeat (and count). now i see exactly when, where and how i'll be using it.
i've read several postings and articles on iterators and itertools, but what
you said just made it all "click".

bryan


Bryan

unread,
Jun 22, 2003, 9:30:18 PM6/22/03
to
oh no...

>>> for i in enumerate(['a', 'b', 'c']): print i
...
(0, 'a')
(1, 'b')
(2, 'c')
>>> for i in zip(count(), ['a', 'b', 'c']): print i
...
(0, 'a')
(1, 'b')
(2, 'c')
>>> for i in izip(count(), ['a', 'b', 'c']): print i
...
(0, 'a')
(1, 'b')
(2, 'c')
>>>


Raymond Hettinger

unread,
Jun 23, 2003, 1:37:51 AM6/23/03
to
"Bryan" <bel...@yahoo.com> wrote in message
news:KKsJa.107828$YZ2.275985@rwcrnsc53...

Oh please! That's just silly.

>>> print 1
1
>>> print range(2)[1]
1
>>> print 22-21
1
>>> print str("1")
1

Of course, general purpose constructs can be made to emulate one
another (for instance, most looping constructs reduce to "if" and "goto").

So, to answer your implied point/question/taunt or whatever it is,
here is the purpose of each and why things are the way they are:

* enumerate(seqn) was added to the builtins to address a common for
accessing list values and list indices at the same time. That need came
up in several PEPs designed to tackle the "loop counter" problem.

* itertools.izip() is designed to be a highly efficient replacement for
zip(). In some circumstances, it is substantially more memory efficient
and faster than zip() which has to be kept in its present form for backwards
compatibilty. For Python 3.0, I'm sure there will be only one -- the relation
of zip() to izip() is about the same as that of range() to xrange().

* itertools.count() is like itertools.repeat() in that it was designed to supply
arguments to imap(), ifilter(), izip(), and other itertools. It allows you to
do things you can't do with enumerate() like:

for checkno, check in izip(count(1000), checks): . . .

tabulate = lambda func: izip(func, count())


Before getting in a twist about these things, try using some of the tools
to get a sense of why they are important. If there is some overlap with
existing tools, remember that they pre-date the iterator protocol which
has done so much to unify and simplify python.

Also, try to avoid a shallow reading of the Zen of Python.
Yes, it says there is there should be only one way to do things.
But the zen is a set of trade-offs. Guido's thoughts on the matter
are well summarized in his keynote slides from PyCon in DC:
http://www.python.org/doc/essays/ppt/pycon2003/pycon2003.ppt

'nuff said,


Raymond Hettinger

Bryan

unread,
Jun 23, 2003, 2:07:47 AM6/23/03
to
"Raymond Hettinger" <vze4...@verizon.net> wrote in message
news:PmwJa.6109$N%6.5...@nwrdny02.gnilink.net...

well, i think i was only half taunting, but i don't think it's silly at
all... i do think that a newbie trying to figure out what to do is going to
have a somewhat tougher time. in my three examples, there are only subtle
differences. i myself would probably use the enumerate one, but after
reading the itertools documentation, i found the izip one first. after i
saw enumerate, it wasn't immediately obvious to me what others would do.
izip has the look and feel of the classic zip. i knew others would easily
be able to read it. enumerate hides the the count() appears simpilar, but
because of hiding the count(), it isn't as obvious. i only brought this up
because in my own personal python experience, i have never encounted this
feeling of "not knowing how others would do it". i wasn't trying to zen-ize
this to death. maybe the documentation should help guide the user about the
issues of backwards compatibily, when to use the classic zip/map etc, and
when to use the new ones, and when to blend the two styles as i did with
the zip example. also, i think the itertools documentation should have a
reference to enumerate even though it's a builtin, and visa-vera.


bryan

0 new messages